#include "mutex.hpp"
#include "cond.hpp"
#include "pthread.hpp"
#include "Log.hpp"
#include <vector>
#include <queue>

namespace PthreadPoolModule
{
    using namespace CondModule;
    using namespace MutexModule;
    using namespace PthreadModel;
    using namespace LogModule;

    size_t dcout = 5;

    template <typename T>
    class Pthreadpool
    {
    private:
        Pthreadpool(size_t cout = dcout)
            : _cout(cout), _isrunning(false), _sleepnum(0)
        {
            for (int i = 0; i < cout; i++)
            {
                _pthreads.emplace_back(
                    [this]()
                    {
                        HandlerTask();
                    });
            }
        }
        void WakeUpAllPthread()
        {
            if (_sleepnum)
                _cond.Broadcast();
        }
        void WakeUpOne()
        {
            _cond.Signal();
            LOG(LogLevel::INFO) << "唤醒一个休眠线程";
        };

        Pthreadpool(const Pthreadpool<T>&)=delete;
        Pthreadpool<T>& operator=(const Pthreadpool<T>&)=delete;
    public:
        static Pthreadpool<T>* GetInstance()
        {
            if(inc==nullptr)
            {
                LockGuard lockguard(_lock);
                LOG(LogLevel::DEBUG)<<"获取单例.....";
                if(inc==nullptr)
                {
                    LOG(LogLevel::DEBUG)<<"首次创建一个实例.....";
                    inc=new Pthreadpool<T>();
                    inc->Start();
                }
            }
            return inc;
        }
        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true;
            for (auto &pthread : _pthreads)
            {
                pthread.start();
            }
        }
        void Stop()
        {
            if (!_isrunning)
                return;
            _isrunning = false;
            WakeUpAllPthread();
        }

        void Join()
        {
            for (auto pthread : _pthreads)
            {
                pthread.Join();
            }
        }
        void HandlerTask()
        {
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            while (1)
            {
                T t;
                {
                    LockGuard lockguard(_mutex);
                    while (_tasks.empty() && _isrunning)
                    {
                        _sleepnum++;
                        _cond.Wait(_mutex);
                        _sleepnum--;
                    }
                    if (!_isrunning && _tasks.empty())
                    {
                        LOG(LogLevel::INFO) << name << "线程池 && 任务队列 退出成功";
                        break;
                    }
                    t = _tasks.front();
                    _tasks.pop();
                }
                t();
            }
        }

        bool Enqueue(const T &in)
        {
            if (_isrunning)
            {
                LockGuard lockguard(_mutex);
                _tasks.push(in);
                if (_sleepnum == _pthreads.size())
                {
                    WakeUpOne();
                }
                return true;
            }
            return false;
        }

    private:
        vector<pthread> _pthreads;
        size_t _cout;
        queue<T> _tasks;
        Cond _cond;
        Mutex _mutex;

        bool _isrunning;
        size_t _sleepnum;

        static Pthreadpool<T> *inc;
        static Mutex _lock;
    };

}

template <typename T>
PthreadPoolModule::Pthreadpool<T>* PthreadPoolModule::Pthreadpool<T>::inc = nullptr;

template <typename T>
PthreadPoolModule::Mutex PthreadPoolModule::Pthreadpool<T>::_lock;